# -*- coding: utf-8 -*-
import json
import logging

import requests
from dateutil import parser
from django.conf import settings
from django.http import HttpResponse
from django.utils.encoding import smart_unicode
from django.views.decorators.http import require_GET, require_POST

from api.preset.handler import view_pay_type, get_fixed_bucket
from api.transaction import handler
from api.transaction.handler import submit_pay_unionagency_v2
from api.transaction.model import available_pay_types
from common.account.model.account import ACCOUNT_STATUS
from common.cache import redis_cache
from common.notification.handler import notify_offline_pay_apply
from common.pay import db as pay_db
from common.pay.model import PAY_STATUS, PAY_TYPE, PAY_SERVICE_NAMES
from common.recharge.db import get_last_recharge
from common.stats.account import get_account_aggr
from common.transaction.model import WITHDRAW_TYPE
from common.transaction.db import get_last_success_pay
from common.utils import exceptions as err
from common.utils.api import (token_required, parse_p, get_client_ip,
                              parse_common_params, check_params, get_city)
from common.utils.decorator import response_wrapper
from common.withdraw import get_available_withdraw_type
from common.withdraw.just_withdraw import generate_sign
from common.preset.db.pay import get_pay_by_pay_type
from common.third.pay.unionagency_v2 import query_pay_info
from common.utils import track_logging

from common.pay.model import PAY_STATUS, CREATED_BY_TYPE

_LOGGER = track_logging.getLogger(__name__)


@require_GET
@response_wrapper
@token_required
def get_transactions(request):
    """
    查看交易记录
    """
    user_id = request.user_id
    query_dct = request.GET.dict()
    try:
        page, size = parse_common_params(query_dct)
        transaction_type = int(
            query_dct['type']) if 'type' in query_dct else None
        start_date = parser.parse(query_dct['start_date'])
    except Exception as e:
        raise err.ParamError(e)

    t_list = handler.get_user_transactions(
        user_id, page, size, transaction_type, start_date)
    data = {
        'list': t_list,
        'page': page,
        'size': len(t_list),
    }
    return data


@require_GET
@response_wrapper
@token_required
def get_last_info(request):
    target_type = request.GET.get('target_type', None)
    info = handler.get_last_withdraw_info(request.user_id, target_type)
    return info


@require_POST
@response_wrapper
@token_required
def submit_withdraw(request):
    param_dct = json.loads(smart_unicode(request.body))
    check_params(
        param_dct,
        ['target_type', 'amount', 'trade_pwd', 'target_info'],
        param_type_dct={'amount': int},
        param_validfunc_dct={'amount': lambda x: x > 0}
    )
    amount = int(param_dct['amount'])
    withdraw_base = int(redis_cache.get_limit_amount())
    max_withdraw = 50000
    if amount < withdraw_base:
        raise err.DataError(u'最低提现金额是 %s 元' % withdraw_base)
    if amount % 10 != 0:
        raise err.DataError(u'提现金额需为10的整数倍')
    if amount > max_withdraw:
        raise err.DataError(u'单笔提现最高5万')
    for k in (ACCOUNT_STATUS.TRADEABLE,):
        if request.user.status & k == 0:
            raise err.PermissionError('status not right')
    if not request.user.phone:
        raise err.PermissionError('need bind phone!')
    if request.user.is_virtual:
        raise err.PermissionError('account not access !')

    user_id = request.user_id
    target_type = int(param_dct['target_type'])
    p = parse_p(request.GET.get('p'))
    if target_type == WITHDRAW_TYPE.BANKCARD:
        param_dct['target_info']['sdk_version'] = '_'.join([p.get('chn', ''), p.get('cvn', '')])
        param_dct['target_info']['ip'] = get_client_ip(request)
        param_dct['target_info']['city'] = get_city(param_dct['target_info']['ip']) or u'海外'
    if target_type not in get_available_withdraw_type():
        raise err.DataError(u'该提现通道暂时关闭，请切换提现方式或稍后重试')
    handler.submit_withdraw(user_id,
                            param_dct['target_type'],
                            param_dct['amount'],
                            param_dct['trade_pwd'],
                            param_dct['target_info'])
    return {}


@require_GET
@response_wrapper
@token_required
def get_withdraw_record(request):
    query_dct = request.GET.dict()
    page, size = parse_common_params(query_dct)
    items = handler.get_withdraw_record(request.user_id, page, size, fix_status=True)
    return {'list': items, 'page': page, 'size': len(items)}


@require_GET
@response_wrapper
@token_required
def get_withdraw_record_v2(request):
    query_dct = request.GET.dict()
    page, size = parse_common_params(query_dct)
    items = handler.get_withdraw_record(request.user_id, page, size, fix_status=False)
    return {'list': items, 'page': page, 'size': len(items)}


@require_GET
@response_wrapper
@token_required
def get_pay_types(request):
    """
    查看可用支付类型
    """
    try:
        platform = request.GET.get('platform')
        version_code = request.GET.get('version_code')
        locale = request.GET.get('locale')
        chn = request.GET.get('chn')
    except:
        raise err.ParamError('pay type wrong')

    if not version_code:
        version_code = -1

    tracks = parse_p(request.GET.get('p'))
    client_chn = chn or tracks.get('chn')

    user_id = request.user_id
    try:
        filtered_available_pay_types = view_pay_type(tracks.get('cvc'), tracks.get('chn'))
    except:

        filtered_available_pay_types = []

    if not filtered_available_pay_types:
        filtered_available_pay_types = filter_available_pay_types(
            user_id, available_pay_types, platform, version_code, locale,
            client_chn)

    client_ip = get_client_ip(request)
    pay_type_list = filter_pay_types_for_risk(
        filtered_available_pay_types, client_chn, client_ip)
    pay_type_list = check_payservice_available(user_id, pay_type_list)
    pay_type_list = check_self_recharge(pay_type_list)

    for item in pay_type_list:
        item['icon'] = get_fixed_bucket(item['icon'])
    last_pay = get_last_success_pay(user_id)
    last_recharge = get_last_recharge(user_id)
    if last_pay:
        if last_recharge and last_recharge.updated_at > last_pay.updated_at:
            last_pay_type = PAY_TYPE.SELF_WECHAT
        else:
            last_pay_type = last_pay.pay_type
    else:
        if last_recharge:
            last_pay_type = PAY_TYPE.SELF_WECHAT
        else:
            # 新用户显示快捷支付
            if pay_type_list:
                last_pay_type = pay_type_list[0]['pay_type']
            else:
                last_pay_type = None

            _LOGGER.info("aaaa {} ".format(pay_type_list))
            for p in pay_type_list:
                if p.get('category') == u'快捷支付':
                    last_pay_type = p['pay_type']
                    break

    data = {
        'list': pay_type_list,
        'last_pay_type': last_pay_type,
        'count': len(pay_type_list)
    }

    # fix client incompatible bug
    if tracks.get('cvc') < 22:
        data['list'] = remove_self_wechat_pay_type(pay_type_list)

    return data


def remove_self_wechat_pay_type(pay_type_list):
    for item in pay_type_list:
        if item.get('pay_type') == PAY_TYPE.SELF_WECHAT:
            item.pop('pay_type')
    return pay_type_list


@require_GET
@response_wrapper
@token_required
def last_unionagent_unsuccess_record(request):
    """
    获取用户上次支付的信息
    :param req:
    :return:
    """
    user_id = request.user_id

    pay_info = handler.get_last_unionagency_record(user_id)
    if not pay_info or pay_info['status'] == PAY_STATUS.DONE:
        return None
    pay_info = query_pay_info(pay_info['id'])
    _LOGGER.info("last_unionagent_unsuccess_record user_id {} {} ".format(user_id, pay_info))
    return pay_info


@require_GET
@response_wrapper
@token_required
def get_type_min_amount(request):
    pay_type = int(request.GET.get('pay_type', 0))
    if pay_type and pay_type in PAY_TYPE.to_dict():
        preset_pay = get_pay_by_pay_type(pay_type)
        return {'min_pay': preset_pay.least_pay, 'max_pay': 10 ** 6}
    return {'min_pay': 0, 'max_pay': 10 ** 6}


def check_payservice_available(user_id, pay_types):
    # 根据userid query_paytypes
    # available_pays = redis_cache.get_available_pays()
    try:
        parameter_dict = {
            'mch_id': settings.JUSTPAY_MCH_ID,
            'user_id': user_id
        }
        parameter_dict['sign'] = generate_sign(parameter_dict, settings.JUSTPAY_API_KEY)
        query_url = settings.QUERY_URL
        res = requests.post(settings.QUERY_URL, data=parameter_dict, timeout=3).text
        res = json.loads(res)
        available_pays = res['data']['list']
    except Exception as e:
        _LOGGER.exception('query_pay_type by user_id error, %s', user_id)
        available_pays = redis_cache.get_available_pays()

    available_sources = [PAY_SERVICE_NAMES.get(ap) for ap in available_pays]
    pay_list = []
    for pay_type in pay_types:
        pt = str(pay_type.get('pay_type'))
        if pt and pt in PAY_SERVICE_NAMES.values():
            if pt in available_sources:
                pay_list.append(pay_type)
        else:
            pay_list.append(pay_type)
    return pay_list


def check_self_recharge(pay_types):
    if not redis_cache.get_self_recharge():
        return pay_types

    result = []
    for item in pay_types:
        if item.get('pay_type') == PAY_TYPE.SELF_WECHAT:
            if not redis_cache.get_recharge_wechat():
                continue
            item = available_pay_types['self_recharge']

        result.append(item)

    return result


def filter_pay_types_for_risk(pay_types, chn, client_ip):
    p_list = []
    for pay_type in pay_types:
        p_list.append(pay_type)
    return p_list


def filter_available_pay_types(user_id, available_pay_types, platform,
                               version_code, locale, chn):
    try:
        if 'test' in chn:
            return [
                available_pay_types[PAY_TYPE.JUSTPAY_TEST],
            ]
    except:
        _LOGGER.info('no p value')
    return [
        available_pay_types[PAY_TYPE.JUSTPAY_ALI],
        available_pay_types[PAY_TYPE.JUSTPAY_QQ],
        # available_pay_types[PAY_TYPE.JUSTPAY_WX],
        available_pay_types[PAY_TYPE.JUSTPAY_UNION],
    ]


@require_POST
@response_wrapper
@token_required
def pay_ready(request):
    """
    获取支付编码
    """
    try:
        param_dct = json.loads(request.body)
        pay_type = int(param_dct.get('type'))
    except:
        raise err.ParamError('pay type wrong')

    if pay_type == 0:  # self recharge
        return {'pay_id': '1001'}
    pay_id = handler.create_pay_id(request.user_id, pay_type)
    return {'pay_id': str(pay_id)}


DAILY_RECHARGE_LIMIT = 100000


@require_POST
@response_wrapper
@token_required
def pay_submit(request, pay_id):
    """
    提交支付，content里面是具体的订单信息，是一个list，每个是一个购买项dict，其中除了
    "activity_type"用来指代彩种以外，其他就是各彩种下单时传递的参数
    """
    param_dct = json.loads(request.body)
    check_params(param_dct, ['pay_amount'], {'content': {}})
    try:
        pay_amount = float(param_dct['pay_amount'])  # 充值金额
        content = param_dct['content']
        sdk_version = param_dct.get('sdk_version')
    except Exception as e:
        raise err.ParamError('pay type wrong %s', e)
    user = request.user
    # trick code for self recharge
    if pay_id == '1001':
        return {
            'open_type': 'app_url',
            'charge_info': available_pay_types['self_recharge']['open_url']
        }
    pay_data = handler.submit_pay(
        user, pay_id, pay_amount, content, sdk_version)
    return pay_data


@require_POST
@response_wrapper
@token_required
def pay_submit_unionagency_v2(request, pay_id):
    param_dct = json.loads(request.body)
    check_params(param_dct,
                 ['pay_amount', 'pay_type', 'account_num', 'account_username', 'account_bank', 'sdk_version'])
    try:
        pay_amount = float(param_dct['pay_amount'])
        pay_type = param_dct['pay_type']
        account_num = param_dct['account_num']
        account_username = param_dct['account_username']
        account_bank = param_dct['account_bank']
        sdk_version = param_dct.get('sdk_version')
    except Exception as e:
        raise err.ParamError('pay type wrong %s', e)
    pay_data = submit_pay_unionagency_v2(request.user, pay_id, pay_amount, sdk_version, pay_type, account_num,
                                         account_username, account_bank)
    return pay_data


@require_POST
@response_wrapper
def fill_unionagent_charge(request):
    params = request.POST.dict()
    if params.get('pay_type') and params.get('pay_type') not in ['bankcard', 'alipay', 'wechat']:
        raise err.ParamError(u'支付类型传参错误')
    res = requests.post(settings.UNIONAGENCY_FILL_URL, params, timeout=5).text
    res_dict = json.loads(res)
    if res_dict['status'] == 0:
        pay = pay_db.get_pay(int(params['out_trade_no']))
        notify_offline_pay_apply(pay.user_id, params.get('amount', 0))
    return res_dict.get('data')


@require_GET
def get_unionagent_page(request, pay_id):
    res = requests.get(settings.UNIONAGENCY_GATEWAY_URL + pay_id + '/', timeout=5).text
    return HttpResponse(res)


@require_GET
@response_wrapper
def get_pay_status(request, pay_id):
    """
    查询支付状态
    """
    pay = handler.view_pay_status(pay_id)
    ext = {} if not pay.extend else json.loads(pay.extend)
    if pay.status != PAY_STATUS.DONE:
        _LOGGER.warn('pay status invalid, pay_id[%s] status[%s]' % (
            pay_id, pay.status))
    data = {
        'status': pay.status,
        'extend': ext
    }
    return data


@require_GET
@response_wrapper
@token_required
def get_limit(req):
    """
    查询限制金额
    """
    amount = redis_cache.get_limit_amount()
    return {'amount': amount}


def check_unionagency_available(pay_list, user_id):
    for idx, pay in enumerate(pay_list):
        if pay['pay_type'] == PAY_TYPE.UNIONAGENCY:
            if not get_account_aggr(user_id)['user_stats'].get("recharge", {}).get("count", 0):
                del pay_list[idx]
            break
    return pay_list
